﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Data;
using System.Data.SqlClient;

namespace BLL
{
    public class Authentication
    {
          
        /// <summary>
        /// Holds the name of the user cookie
        /// </summary>
        private const string USER_COOKIE_NAME = "UserCookie";
        /// <summary>
        /// Performs a user login to the system
        /// </summary>
        /// <param name="Username"></param>
        /// <param name="Password"></param>
        /// <returns></returns>
        public static BO.User Login(string UserIdentifier, string Password)
        {
            return Login(UserIdentifier, Password, false);
        }
        /// <summary>
        /// Performs a user login to the system. Allows you to "remmember" the user in a cookie
        /// </summary>
        /// <param name="Username"></param>
        /// <param name="Password"></param>
        /// <param name="IsRemember"></param>
        /// <returns></returns>
        public static BO.User Login(string UserIdentifier, string Password, bool IsRemember)
        {
            Users.SqlQuery q = BLL.Users.Get()
                                       .Where(BLL.Users.Columns.Password, BLL.Actions.Equal, BLL.Encryption.Encrypt(Password))
                                       .Where(BLL.Users.Columns.StatusEnum, Actions.Equal,BLL.EntityStatuses.Active);
                
            if(System.Configuration.ConfigurationManager.AppSettings["UserIdentifier"] == "Email")
                q.Where(BLL.Users.Columns.Email, BLL.Actions.Equal, UserIdentifier);
            else q.Where(BLL.Users.Columns.Username, BLL.Actions.Equal, UserIdentifier);

            List<BO.User> userCollection = q.Select();

            if (userCollection.Count != 1)
            {
                ClearUserCookie();
                return null;
            }

            SetUserCookie(userCollection[0].ID, UserIdentifier, IsRemember);

            return userCollection[0];
        }
        /// <summary>
        /// Logs the user out
        /// </summary>
        public static void Logout()
        {
            ClearUserCookie();
        }
        /// <summary>
        /// Clear the user cookie from both memory and the client's computer.
        /// </summary>
        private static void ClearUserCookie()
        {
            HttpCookie UserCookie = new System.Web.HttpCookie(USER_COOKIE_NAME);

            HttpContext.Current.Request.Cookies.Clear();
            HttpContext.Current.Response.Cookies.Add(UserCookie);
        }
        /// <summary>
        /// Sets the user cookie on the client computer.
        /// if IsRemember is true - set the expire date of the cookie to
        /// two years from now
        /// </summary>
        /// <param name="id"></param>
        /// <param name="username"></param>
        /// <param name="IsRemember"></param>
        public static void SetUserCookie(int id, string UserIdentifier, bool IsRemember)
        {
            HttpCookie UserCookie = new System.Web.HttpCookie(USER_COOKIE_NAME);

            UserCookie.Values.Add("u", BLL.Encryption.Encrypt(UserIdentifier));
            UserCookie.Values.Add("i", BLL.Encryption.Encrypt(id.ToString()));

            if (IsRemember)
                UserCookie.Expires = DateTime.Now.AddYears(2);

            HttpContext.Current.Response.Cookies.Add(UserCookie);
        }

        /// <summary>
        /// Get the authenticated user's ID. If the user isn't authenticated returns null
        /// </summary>
        public static int? CurrentUserID
        {
            get
            {
                HttpCookie userCookie = GetUserCookieFromRequest();
                
                //if there is no coockie in the request, check if the user has logged in , and has a coockie in the response.
                if (userCookie == null || string.IsNullOrEmpty(userCookie["i"]))
                    userCookie = GetUserCookieFromResponse();

                if (userCookie == null)
                    return null;
                if (string.IsNullOrEmpty(userCookie["i"]))
                    return null;

                try
                {
                    return Convert.ToInt32(BLL.Encryption.Decrypt(userCookie["i"]));
                }
                catch
                {
                    return null;
                }

            }
        }

        /// <summary>
        /// Gets the current authenticated user.
        /// </summary>
        /// <returns></returns>
        public static BO.User GetCurrentUser()
        {
            if (CurrentUserID.HasValue)
                return BLL.Users.GetByID(CurrentUserID.Value);
            else return null;

        }

        /// <summary>
        /// Get the user cookie from the request
        /// </summary>
        /// <returns></returns>
        private static HttpCookie GetUserCookieFromRequest()
        {
            return HttpContext.Current.Request.Cookies[USER_COOKIE_NAME];
        }
        /// <summary>
        /// Get the user cookie from the response
        /// </summary>
        /// <returns></returns>
        private static HttpCookie GetUserCookieFromResponse()
        {
            return HttpContext.Current.Response.Cookies[USER_COOKIE_NAME];
        }
        /// <summary>
        /// Checks whether the user is authenticated
        /// </summary>
        /// <returns></returns>
        public static bool IsCurrentUserAuthenticated()
        {
            return CurrentUserID.HasValue;
        }
        /// <summary>
        /// Checks whether the user is authorized for a given url
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
       

        public static void CheckAuthentication()
        {
            if (!IsCurrentUserAuthenticated())
                HttpContext.Current.Response.Redirect(String.Format("Login.aspx?gotoURL={0}",
                    HttpUtility.UrlEncode(HttpContext.Current.Request.RawUrl)
                    ));
        }

        public static bool IsCurrentUserAuthorized()
        {
            if (IsCurrentUserAuthenticated())
            {
                return DAL.Authentication.IsUserAuthorized(CurrentUserID.Value, HttpContext.Current.Request.CurrentExecutionFilePath);
            }
            return false;
        }


        public static bool IsCurrentUserInPermissionGroup(string PermissionGroupName)
        {
            if (IsCurrentUserAuthenticated())
                return IsUserInPermissionGroup(CurrentUserID.Value, PermissionGroupName);
            return false;
        }
        public static bool IsUserInPermissionGroup(int userID, string PermissionGroupName)
        {
            return DAL.Authentication.IsUserInPermissionGroup(userID, PermissionGroupName);
        }
    }
}

namespace DAL
{
    public static class Authentication
    {
        internal static bool IsUserAuthorized(int UserID, string URL)
        {
            string cmd;

            cmd = @"
SELECT Pages.* 
FROM 
 User_PermissionGroup 
INNER JOIN 
 Page_PermissionGroup ON Page_PermissionGroup.PermissionGroupID = User_PermissionGroup.PermissionGroupID
INNER JOIN 
 Pages ON Pages.ID = Page_PermissionGroup.PageID
WHERE
 UserID = @UserID AND 
 FullPath = @URL;";

            DataTable dt;

            dt = DBHelper.GetTable(cmd, CommandType.Text,
                                   new SqlParameter("UserID", UserID),
                                   new SqlParameter("URL", URL));

            return dt.Rows.Count >= 1;
        }

        internal static bool IsUserInPermissionGroup(int userID, string PermissionGroupName)
        {
            string cmd = @"
SELECT
	COUNT(Users.ID)
FROM
	Users
INNER JOIN
	User_PermissionGroup ON User_PermissionGroup.UserID = Users.ID
INNER JOIN
	PermissionGroups ON PermissionGroups.ID = User_PermissionGroup.PermissionGroupID
WHERE
	PermissionGroups.Name = @PermissionGroupName
AND Users.ID = @UserID";

            var p = new SqlParameter[] { new SqlParameter("PermissionGroupName", PermissionGroupName)
                                        , new SqlParameter("UserID", userID) };

            int count = (int)DBHelper.GetScalar(cmd, p);

            return count == 1;            
        }
    }
}
